#ifndef STACKALLOCATOR_H_INCLUDED
#define STACKALLOCATOR_H_INCLUDED

#include "Atomic.h"

namespace CEngine
{

namespace MemoryManager {
    void initialize(void);
}

class StackAllocator {
    public:

        ///Stack Markers. Marks the current top of the stack
        ///You can only roll back to a stack marker.
        typedef U64 Marker;

        ///Creates a stack of the given size.
        StackAllocator(U64 stackSize);

        ///Copies the old stack to the new one.
        StackAllocator(const StackAllocator& stack);

        ///Copies the old stack to the new one.
        ///MUST BE OF EQUAL OR GREATER SIZE THAN THE OLD STACK.
        StackAllocator(const StackAllocator& stack, U64 stackSize);

        ///deletes the stack.
        ~StackAllocator(void);

        ///returns a pointer to a block of memory of the given size.
        void*
        alloc(U64 bytes);

        ///returns a pointer to an aligned block of memory of the given size (wastes alignment number of bytes).
        void*
        alignedAlloc(U64 bytes, U64 alignment);

        ///returns the number of free bytes left.
        U64
        getFreeBytes(void);

        ///returns the total number of bytes in the stack.
        U64
        getTotalBytes(void);

        ///returns a marker to the top of the stack.
        Marker
        getMarker(void) const;

        ///sets the top of the stack to the marker.
        void
        freeToMarker(Marker marker);

        ///resets the stack.
        void
        clear(void);

        friend void MemoryManager::initialize(void);

    private:

        void*   stackPointer;
        void*   stackTop;
        U64     freeBytes, totalBytes;
};

inline U64
StackAllocator::getFreeBytes(void) {
    return freeBytes;
}

inline U64
StackAllocator::getTotalBytes(void) {
    return totalBytes;
}

inline StackAllocator::Marker
StackAllocator::getMarker(void) const {
    return (Marker)stackTop;
}

}

#endif // STACKALLOCATOR_H_INCLUDED
